package de.sendorian.app.forumArchive;

import static de.sendorian.app.forumArchive.renamer.Renamers.nothing;
import static org.hamcrest.Matchers.anything;

import java.text.SimpleDateFormat;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.hamcrest.Matcher;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import de.sendorian.app.forumArchive.domain.Forum;
import de.sendorian.app.forumArchive.domain.Post;
import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.finder.Finder;
import de.sendorian.app.forumArchive.renamer.FileRenamer;
import de.sendorian.util.matcher.PropertyMatcher;

@Component
public abstract class Config {

	private static final Logger LOG = Logger.getLogger(Config.class);
	
	private static final PropertyMatcher property = new PropertyMatcher();
	
	protected static Config config;

	private String downloadDir;
	private String month;
	private String sEndDate;
	private String sStartDate;
	protected DateTime startDate;
	protected DateTime endDate;
	
	public abstract String getBaseUrl();

	public abstract SimpleDateFormat getDateFormat();

	public abstract Pattern getDatePattern();

	public FileRenamer getDefaultRenamer() {
		return nothing();
	}

	public String getDownloadDir() {
		return downloadDir;
	}

	protected DateTime getEndDate() {
		if (sEndDate != null) {
			endDate = new DateTime(sEndDate);
		} else {
			try {
				endDate = getStartDate().dayOfMonth().withMaximumValue();
				LOG.info("Configured end date: " + endDate);
			} catch (Exception e) {
				LOG.error("Could not parse end_date property or "
						+ "property does not exist.", e);
			}
		}
		return endDate;
	}

	public abstract Finder<String, Forum> getForumFinder();

	protected String getMonth() {
		return month;
	}

	public abstract Finder<Topic, Post> getPostFinder();

	public Matcher<Post> getPostMatcher() {
		return anything();
	}

	protected DateTime getStartDate() {
		if (sStartDate != null) {
			startDate = new DateTime(sStartDate);
		} else {
			try {
				String propertyMonth = getMonth();
				if (propertyMonth == null) {
					LOG.info("Properties 'month' and 'start_date' not set. " +
							"Using actual month as default.");
					startDate = new DateTime().dayOfMonth().withMinimumValue();
				} else {
					startDate = new DateTime(propertyMonth + "-01");
				}
				LOG.info("Configured start date: " + startDate);
			} catch (Exception e) {
				LOG.error("Could not parse start.date property or property does not exist.",
								e);
			}
		}
		return startDate;
	}

	public abstract Finder<Forum, Topic> getTopicFinder();

	public Matcher<Topic> getTopicMatcher() {
		return anything();
	}
	
	@Value("#{props['download_dir']}")
	public void setDownloadDir(String downloadDir) {
		this.downloadDir = (property.matches(downloadDir) ? "" : downloadDir);
	}

	@Value("#{props['end_date']}")
	public void setEndDate(String endDate) {
		this.sEndDate = (property.matches(endDate) ? null : endDate);
	}

	@Value("#{props['month']}")
	public void setMonth(String month) {
		this.month = (property.matches(month) ? null : month);
	}

	@Value("#{props['start_date']}")
	public void setStartDate(String startDate) {
		this.sStartDate = (property.matches(startDate) ? null : startDate);
	}

}
